package com.cyy.util


import java.awt.AWTException
import java.awt.Color
import java.awt.Cursor
import java.awt.Dimension
import java.awt.FlowLayout
import java.awt.Graphics
import java.awt.Graphics2D
import java.awt.Point
import java.awt.Rectangle
import java.awt.Robot
import java.awt.Toolkit
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import java.awt.event.KeyEvent
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import java.awt.event.MouseMotionListener
import java.awt.image.BufferedImage

import javax.swing.JButton
import javax.swing.JComponent
import javax.swing.JFrame
import javax.swing.JPanel
import javax.swing.KeyStroke

import com.cyy.learn.qRCodeBuilder.QRCodeBuilderController

import javafx.embed.swing.SwingFXUtils

class ScreenShoter(codeBuilderController: QRCodeBuilderController) : JFrame() {

    init {
        size = SShoterConfig.SCREEN_SIZE
        isUndecorated = true
        setLocation(0, 0)
        setLocationRelativeTo(null)
        val pane = Shoter(codeBuilderController, this)
        contentPane = pane
        isVisible = true
    }

    companion object {
        private val serialVersionUID = 2824099274822727350L
    }
}

internal class Shoter(private val codeBuilderController: QRCodeBuilderController, private val shoter: JFrame) : JPanel() {
    var screenImg: BufferedImage? = null
    private var _start = Point(0, 0)
    private var _end = Point(1, 1)
    private var buttons: JPanel? = null
    private var buttonSave: JButton? = null
    private var buttonCancel: JButton? = null
    private var buttonExit: JButton? = null
    private var operationStatus = SShoterConfig.MOUSE_DRAG
    private var _moveStart = Point()
    private var rectSize: Dimension? = null
    private var buttonsPosition: Point? = null

    val newImage: BufferedImage
        get() =
            this.screenImg!!.getSubimage(_start.getX().toInt(), _start.getY().toInt(), (_end.getX() - _start.getX()).toInt(),
                    (_end.getY() - _start.getY()).toInt())

    init {
        snapshot()
        layout = null
        background = Color(200, 200, 200)
        this.addMouseListener(RectListener())
        this.addMouseMotionListener(RectDragListener())
        add(getButtons())
        buttons!!.size = SShoterConfig.BUTTONS_PANEL_SIZE
        buttons!!.isVisible = false
        isVisible = true
    }

    fun snapshot() {
        try {
            val robot = Robot()
            screenImg = robot.createScreenCapture(
                    Rectangle(0, 0, SShoterConfig.SCREEN_SIZE.width, SShoterConfig.SCREEN_SIZE.height))
        } catch (e: AWTException) {
            e.printStackTrace()
        }

    }

    fun getButtons(): JPanel {
        buttons = JPanel()
        buttons!!.layout = FlowLayout(FlowLayout.RIGHT)
        buttons!!.background = Color(200, 200, 200)

        buttonSave = JButton("Save")
        // buttonSave
        buttonSave!!.size = SShoterConfig.BUTTONS_SIZE
        val buttonSaveLis = object : ActionListener {
            override fun actionPerformed(e: ActionEvent) {
                try {
                    // ImageIO.write(getNewImage(), fileExtension, file);
                    codeBuilderController.snapshotActionCallBack(SwingFXUtils.toFXImage(newImage, null))
                    buttons!!.isVisible = false
                    _start = Point(0, 0)
                    _end = Point(0, 0)
                    shoter.isVisible = false
                    shoter.dispose()
                } catch (e1: Exception) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace()
                }

            }

        }
        buttons!!.add(buttonSave)
        buttonSave!!.addActionListener(buttonSaveLis)

        buttonSave!!.registerKeyboardAction(buttonSaveLis, KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK),
                JComponent.WHEN_IN_FOCUSED_WINDOW)

        buttonCancel = JButton("Cancel")
        buttonCancel!!.size = SShoterConfig.BUTTONS_SIZE
        val cancelLis = object : ActionListener {
            override fun actionPerformed(e: ActionEvent) {
                _start = Point(0, 0)
                _end = Point(0, 0)
                buttons!!.isVisible = false
                this@Shoter.cursor = SShoterConfig.CURSOR_NORMAL
                operationStatus = SShoterConfig.MOUSE_DRAG
                this@Shoter.repaint()
            }
        }
        buttonCancel!!.addActionListener(cancelLis)
        buttonCancel!!.registerKeyboardAction(cancelLis, KeyStroke.getKeyStroke(KeyEvent.VK_D, KeyEvent.CTRL_DOWN_MASK),
                JComponent.WHEN_IN_FOCUSED_WINDOW)

        buttons!!.add(buttonCancel)
        // exit
        buttonExit = JButton("Exit")
        buttonExit!!.size = SShoterConfig.BUTTONS_SIZE
        buttons!!.add(buttonExit)
        val buttonExitLis = object : ActionListener {
            override fun actionPerformed(arg0: ActionEvent) {
                codeBuilderController.snapshotActionCallBack(null)
                shoter.isVisible = false
                shoter.dispose()
            }
        }
        buttonExit!!.addActionListener(buttonExitLis)
        buttonExit!!.registerKeyboardAction(buttonExitLis, KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK),
                JComponent.WHEN_IN_FOCUSED_WINDOW)
        return buttons!!

    }

    public override fun paintComponent(comp: Graphics) {
        val comp2D = comp as Graphics2D
        comp2D.drawImage(screenImg, 0, 0, this)
        comp2D.color = Color(0, 0, 0, 100)
        comp2D.fill(Rectangle(0, 0, SShoterConfig.SCREEN_SIZE.width, SShoterConfig.SCREEN_SIZE.height))

        /*
                * comp2D.setColor(new Color( 0, 0, 0)); BasicStroke stroke = new
                * BasicStroke(1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER);
                * comp2D.setStroke(stroke);
                *
                * Rectangle _rect = new Rectangle(_start, new Dimension(_end.x - _start.x,
                * _end.y - _start.y)); comp2D.draw(_rect); Color ColorFill = new Color(255,
                * 255, 255, 0); comp2D.setColor(ColorFill); comp2D.fill(_rect);
                * comp2D.drawImage(getNewImage(), _start.x, _start.y, this);
                */

        if (_end.x - _start.x > 0 && _end.y - _start.y > 0) {
            comp2D.drawImage(newImage, _start.x, _start.y, this)
        }
    }

    private inner class RectListener : MouseAdapter() {
        override fun mousePressed(e: MouseEvent?) {
            if (operationStatus == SShoterConfig.MOUSE_MOVE) {
                _moveStart = Point((e!!.x - _start.getX()).toInt(), (e!!.y - _start.getY()).toInt())
                buttons!!.isVisible = true
            } else if (operationStatus == SShoterConfig.MOUSE_DRAG) {
                _start = e!!.point
                _end = e!!.point
                // hidden the buttons
                buttons!!.isVisible = false
            }
        }

        override fun mouseReleased(e: MouseEvent?) {
            if (operationStatus == SShoterConfig.MOUSE_DRAG) {
                _end = e!!.point
                rectSize = Dimension((_end.getX() - _start.getX()).toInt(), (_end.getY() - _start.getY()).toInt())
                setButtonsPosition()
                buttons!!.isVisible = true
                operationStatus = SShoterConfig.MOUSE_NORMAL
                this@Shoter.repaint()
            }

        }
    }

    /**
     * Mouse Move Listener
     */
    private inner class RectDragListener : MouseMotionListener {
        override fun mouseDragged(e: MouseEvent) {
            if (operationStatus == SShoterConfig.MOUSE_DRAG) {
                _end = e.point
            } else if (operationStatus == SShoterConfig.MOUSE_MOVE) {
                // _moveTemp = _moveStart;
                // _moveEnd = e.getPoint();
                if ((e.x - _moveStart.getX() >= 0 && e.x - _moveStart.x + rectSize!!.width <= SShoterConfig.SCREEN_SIZE.width)) {
                    _start.x = e.x - _moveStart.x
                    _end.x = _start.x + rectSize!!.width
                } else if (e.x - _moveStart.getX() < 0) {
                    _start.x = 0
                } else if (e.x - _moveStart.x + rectSize!!.width > SShoterConfig.SCREEN_SIZE.width) {
                    _end.x = SShoterConfig.SCREEN_SIZE.width
                }
                if ((e.y - _moveStart.getY() >= 0 && e.y - _moveStart.y + rectSize!!.height <= SShoterConfig.SCREEN_SIZE.height)) {
                    _start.y = e.y - _moveStart.y
                    _end.y = _start.y + rectSize!!.height
                } else if (e.y - _moveStart.getY() < 0) {
                    _start.y = 0
                } else if (e.y - _moveStart.y + rectSize!!.height > SShoterConfig.SCREEN_SIZE.height) {
                    _end.y = SShoterConfig.SCREEN_SIZE.height
                }
                // rectSize.setSize((int) (_end.getX() - _start.getX() ), (int)(_end.getY() -
                // _start.getY() ));
            } else if (operationStatus == SShoterConfig.MOUSE_MOVE_W) {
                _start.x = e.x
                rectSize!!.setSize((_end.getX() - _start.getX()).toInt(), (_end.getY() - _start.getY()).toInt())
            } else if (operationStatus == SShoterConfig.MOUSE_MOVE_N) {

                _start.y = e.y
                rectSize!!.setSize((_end.getX() - _start.getX()).toInt(), (_end.getY() - _start.getY()).toInt())
            } else if (operationStatus == SShoterConfig.MOUSE_MOVE_E) {

                _end.x = e.x
                rectSize!!.setSize((_end.getX() - _start.getX()).toInt(), (_end.getY() - _start.getY()).toInt())
            } else if (operationStatus == SShoterConfig.MOUSE_MOVE_S) {

                _end.y = e.y
                rectSize!!.setSize((_end.getX() - _start.getX()).toInt(), (_end.getY() - _start.getY()).toInt())
            }
            setButtonsPosition()
            this@Shoter.repaint()
        }

        override fun mouseMoved(e: MouseEvent) {
            if (operationStatus == SShoterConfig.MOUSE_DRAG) {
                return
            }
            // in the sub image
            if ((e.x > _start.getX() + SShoterConfig.MOVE_EDGE && e.x < _end.getX() - SShoterConfig.MOVE_EDGE
                            && e.y > _start.getY() + SShoterConfig.MOVE_EDGE
                            && e.y < _end.getY() - SShoterConfig.MOVE_EDGE)) {

                this@Shoter.cursor = SShoterConfig.CURSOR_MOVE

                operationStatus = SShoterConfig.MOUSE_MOVE

                // out the sub image
            } else if ((e.x < _start.getX() || e.x > _end.getX() || e.y < _start.getY()
                            || e.y > _end.getY())) {
                this@Shoter.cursor = SShoterConfig.CURSOR_NORMAL
                // in the sub image edge area
            } else {
                if (e.x >= _start.getX() && e.x <= _start.getX() + SShoterConfig.MOVE_EDGE) {
                    if (e.y >= _start.getY() && e.y <= _start.getY() + SShoterConfig.MOVE_EDGE) {

                        operationStatus = SShoterConfig.MOUSE_MOVE_WN
                        this@Shoter.cursor = SShoterConfig.NW_RESIZE_CURSOR

                    } else if ((e.y >= _start.getY() + SShoterConfig.MOVE_EDGE && e.y <= _end.getY() - SShoterConfig.MOVE_EDGE)) {

                        operationStatus = SShoterConfig.MOUSE_MOVE_W
                        this@Shoter.cursor = SShoterConfig.W_RESIZE_CURSOR

                    } else if (e.y >= _end.getY() - SShoterConfig.MOVE_EDGE && e.y <= _end.getY()) {

                        operationStatus = SShoterConfig.MOUSE_MOVE_WS
                        this@Shoter.cursor = SShoterConfig.SW_RESIZE_CURSOR
                    }

                } else if ((e.x > _start.getX() + SShoterConfig.MOVE_EDGE && e.x < _end.getX() - SShoterConfig.MOVE_EDGE)) {
                    if (e.y >= _start.getY() && e.y <= _start.getY() + SShoterConfig.MOVE_EDGE) {

                        operationStatus = SShoterConfig.MOUSE_MOVE_N
                        this@Shoter.cursor = SShoterConfig.N_RESIZE_CURSOR
                    } else {

                        operationStatus = SShoterConfig.MOUSE_MOVE_S
                        this@Shoter.cursor = SShoterConfig.S_RESIZE_CURSOR
                    }

                } else {
                    if (e.y >= _start.getY() && e.y <= _start.getY() + SShoterConfig.MOVE_EDGE) {
                        operationStatus = SShoterConfig.MOUSE_MOVE_WS
                        this@Shoter.cursor = SShoterConfig.NE_RESIZE_CURSOR
                    } else if ((e.y >= _start.getY() + SShoterConfig.MOVE_EDGE && e.y <= _end.getY() - SShoterConfig.MOVE_EDGE)) {

                        operationStatus = SShoterConfig.MOUSE_MOVE_E
                        this@Shoter.cursor = SShoterConfig.E_RESIZE_CURSOR

                    } else if (e.y >= _end.getY() - SShoterConfig.MOVE_EDGE && e.y <= _end.getY()) {

                        operationStatus = SShoterConfig.MOUSE_MOVE_ES
                        this@Shoter.cursor = SShoterConfig.SE_RESIZE_CURSOR
                    }

                }
            }

        }
    }

    fun setButtonsPosition() {
        buttonsPosition = Point()
        if (_end.y + SShoterConfig.BUTTONS_PANEL_SIZE.getHeight() < SShoterConfig.SCREEN_SIZE.getHeight()) {
            buttonsPosition!!.y = _end.getY().toInt()
        } else {
            buttonsPosition!!.y = (_end.y - SShoterConfig.BUTTONS_PANEL_SIZE.getHeight()).toInt()
        }
        if (_end.getX() - SShoterConfig.BUTTONS_PANEL_SIZE.getWidth() >= SShoterConfig.BUTTONS_PANEL_SIZE.getWidth()) {
            buttonsPosition!!.x = (_end.x - SShoterConfig.BUTTONS_PANEL_SIZE.getWidth()).toInt()
        } else {
            buttonsPosition!!.x = _start.getX().toInt()
        }
        buttons!!.location = buttonsPosition!!
    }

    companion object {
        private val serialVersionUID = 6749535851395089903L
    }
}

internal object SShoterConfig {
    // screen size
    val SCREEN_SIZE = Toolkit.getDefaultToolkit().screenSize

    // frame button size
    val FRAME_BUTTON_SIZE = Dimension(60, 20)
    val FRAME_LABEL_SIZE = Dimension(200, 30)

    // buttons
    // buttons panel
    val BUTTONS_PANEL_SIZE = Dimension(210, 40)

    val BUTTONS_SIZE = Dimension(60, 20)

    // the status of the operation

    val MOUSE_DRAG = 0
    val MOUSE_MOVE = 1
    val MOUSE_NORMAL = 2

    // move state
    val MOUSE_MOVE_W = 11

    val MOUSE_MOVE_WN = 12
    val MOUSE_MOVE_WS = 13

    val MOUSE_MOVE_E = 14

    val MOUSE_MOVE_EN = 15
    val MOUSE_MOVE_ES = 16

    val MOUSE_MOVE_N = 17
    val MOUSE_MOVE_S = 18

    // the edge of the move
    val MOVE_EDGE = 10

    // the default image type
    val DEFAULT_IMAGE_EXTENSION = "png"

    // cursors
    val CURSOR_NORMAL = Cursor(Cursor.DEFAULT_CURSOR)
    val CURSOR_MOVE = Cursor(Cursor.MOVE_CURSOR)

    val NW_RESIZE_CURSOR = Cursor(Cursor.NW_RESIZE_CURSOR)
    val W_RESIZE_CURSOR = Cursor(Cursor.W_RESIZE_CURSOR)
    val SW_RESIZE_CURSOR = Cursor(Cursor.SW_RESIZE_CURSOR)
    val N_RESIZE_CURSOR = Cursor(Cursor.N_RESIZE_CURSOR)
    val S_RESIZE_CURSOR = Cursor(Cursor.S_RESIZE_CURSOR)
    val NE_RESIZE_CURSOR = Cursor(Cursor.NE_RESIZE_CURSOR)
    val E_RESIZE_CURSOR = Cursor(Cursor.E_RESIZE_CURSOR)
    val SE_RESIZE_CURSOR = Cursor(Cursor.SE_RESIZE_CURSOR)
}